extends State
class_name PlayerStateDash

# 重构后的玩家冲刺状态 - 简化逻辑，使用Timer节点

const MAX_CHARGE_TIME: float = 0.1  # 最大蓄力时间
const DASH_DURATION: float = 0.1    # 冲刺持续时间
const EASE_FACTOR: float = 2.0      # 缓动因子

@export var dash_input_threshold: float = 0.5 # 阈值，用于量化模拟输入到 -1/0/1（可调）
@export var dash_input_recover_time: float = 0.06 # 冲刺后多久恢复左右移动输入（应小于 DASH_DURATION）

var charge_timer: Timer
var dash_timer: Timer
var dash_direction: Vector2 = Vector2.ZERO
var is_charging: bool = true
var is_dashing: bool = false
var input_handler: InputHandler
var current_data:Dictionary
var recover_timer: Timer

# 八方向枚举（从右顺时针）
enum DashDir {
	DIR_RIGHT = 0,
	DIR_DOWN_RIGHT = 1,
	DIR_DOWN = 2,
	DIR_DOWN_LEFT = 3,
	DIR_LEFT = 4,
	DIR_UP_LEFT = 5,
	DIR_UP = 6,
	DIR_UP_RIGHT = 7,
}
var dash_dir_enum: int = -1

func _dir_enum_to_vector(e: int) -> Vector2:
	match e:
		DashDir.DIR_RIGHT:
			return Vector2(1, 0)
		DashDir.DIR_DOWN_RIGHT:
			return Vector2(1, 1).normalized()
		DashDir.DIR_DOWN:
			return Vector2(0, 1)
		DashDir.DIR_DOWN_LEFT:
			return Vector2(-1, 1).normalized()
		DashDir.DIR_LEFT:
			return Vector2(-1, 0)
		DashDir.DIR_UP_LEFT:
			return Vector2(-1, -1).normalized()
		DashDir.DIR_UP:
			return Vector2(0, -1)
		DashDir.DIR_UP_RIGHT:
			return Vector2(1, -1).normalized()
	return Vector2.ZERO

func _vector_to_dir_enum(v: Vector2) -> int:
	if v.length() < 0.001:
		return -1
	var ang = rad_to_deg(atan2(v.y, v.x))
	var idx = int(round(ang / 45.0))
	idx = (idx % 8 + 8) % 8
	# idx 0 => 0 deg => RIGHT; mapping consistent with DashDir order
	return idx

func _snap_to_eight(v: Vector2) -> Vector2:
	var e = _vector_to_dir_enum(v)
	if e >= 0:
		return _dir_enum_to_vector(e)
	return Vector2.ZERO

func enter(_data: Dictionary = {}) -> void:
	# 消耗能量
	#character.current_energy -= character.dash_cost
	character.velocity = Vector2.ZERO
	if _data.is_empty():
		character.low_gravity = true
	else:
		character.no_gravity = true
	
	# 创建计时器
	_setup_timers()
	
	# 获取输入处理器
	input_handler = character.get_node("InputHandler") as InputHandler
	if input_handler:
		# 监听 dash_released，并监听 movement_input 以在蓄力阶段响应方向变化
		if not input_handler.dash_released.is_connected(_on_dash_released):
			input_handler.dash_released.connect(_on_dash_released)
		# 进入冲刺时，确保临时断开普通移动处理函数，避免立即移动
		if input_handler.movement_input.is_connected(_on_movement_move_input):
			input_handler.movement_input.disconnect(_on_movement_move_input)
		if not input_handler.movement_input.is_connected(_on_movement_input):
			input_handler.movement_input.connect(_on_movement_input)
	
	# 开始蓄力阶段
	is_charging = true
	is_dashing = false

	# 冲刺方向优先使用传入的 "direction"（可以是枚举 int 或 Vector2），其次使用 dash_direction 或按键快照
	dash_dir_enum = -1
	if _data.has("direction"):
		var d = _data.get("direction")
		if typeof(d) == TYPE_INT:
			dash_dir_enum = int(d)
			dash_direction = _dir_enum_to_vector(dash_dir_enum)
		elif typeof(d) == TYPE_VECTOR2:
			dash_direction = d.normalized()
			dash_dir_enum = _vector_to_dir_enum(dash_direction)
		else:
			dash_direction = character.heading
			dash_dir_enum = _vector_to_dir_enum(dash_direction)
		# 直接执行冲刺（传入方向时立即冲刺）
		current_data = _data
		_execute_dash()
		return

	# 若没有传入方向，尝试读取 _data 中的旧键（兼容）
	elif _data.has("dash_direction"):
		var dd = _data.get("dash_direction")
		if typeof(dd) == TYPE_VECTOR2:
			dash_direction = dd.normalized()
			dash_dir_enum = _vector_to_dir_enum(dash_direction)
		else:
			dash_direction = character.heading
			dash_dir_enum = _vector_to_dir_enum(dash_direction)
		current_data = _data
		_execute_dash()
		return
		
		# 否则根据当前按键快照来决定（使用 InputHandler 而不是直接调用 Input）
	character.consume_dash()
	var snap_vec = Vector2.ZERO
	if input_handler:
		var v = input_handler.get_current_movement()
		# 量化到 -1/0/1，避免模拟输入的微小值导致误判为斜向
		var qx = 0
		if v.x > dash_input_threshold:
			qx = 1
		elif v.x < -dash_input_threshold:
			qx = -1
		var qy = 0
		if v.y > dash_input_threshold:
			qy = 1
		elif v.y < -dash_input_threshold:
			qy = -1
		snap_vec = Vector2(qx, qy)
	if snap_vec.length() > 0:
		dash_direction = _snap_to_eight(snap_vec)
		dash_dir_enum = _vector_to_dir_enum(dash_direction)
	else:
		dash_direction = character.heading
		dash_dir_enum = _vector_to_dir_enum(dash_direction)

	# 开始计时与播放蓄力动画
	charge_timer.start()
	animation.play("dash_charge")
	current_data = _data

func exit() -> void:
	# 清理状态
	if character.low_gravity:
		character.low_gravity = false
	elif character.no_gravity:
		character.no_gravity = false
	character.is_dash = false
	
	
	# 清理计时器
	if charge_timer:
		charge_timer.queue_free()
	if dash_timer:
		dash_timer.queue_free()
	if recover_timer:
		recover_timer.queue_free()
	
	# 断开信号
	if input_handler:
		if input_handler.movement_input.is_connected(_on_movement_input):
			input_handler.movement_input.disconnect(_on_movement_input)
		# 退出时也断开普通移动回调，避免遗留连接
		if input_handler.movement_input.is_connected(_on_movement_move_input):
			input_handler.movement_input.disconnect(_on_movement_move_input)
		if input_handler.dash_released.is_connected(_on_dash_released):
			input_handler.dash_released.disconnect(_on_dash_released)

func update(_delta: float) -> void:
	# 状态更新逻辑
	pass

func physics_update(_delta: float) -> void:
	# 物理更新由冲刺逻辑处理
	pass

# 设置计时器
func _setup_timers() -> void:
	# 蓄力计时器
	charge_timer = Timer.new()
	charge_timer.wait_time = MAX_CHARGE_TIME
	charge_timer.one_shot = true
	charge_timer.timeout.connect(_on_charge_timeout)
	add_child(charge_timer)
	
	# 冲刺计时器
	dash_timer = Timer.new()
	dash_timer.wait_time = DASH_DURATION
	dash_timer.one_shot = true
	dash_timer.timeout.connect(_on_dash_timeout)
	add_child(dash_timer)

# 处理移动输入（蓄力方向）
func _on_movement_input(direction: Vector2) -> void:
	# 不再累加；如果玩家在蓄力阶段改变输入，则实时更新为最近方向并向八方向靠齐
	if is_charging:
		# 量化输入以避免模拟摇杆的小幅漂移导致斜向判定
		var qx = 0
		if direction.x > dash_input_threshold:
			qx = 1
		elif direction.x < -dash_input_threshold:
			qx = -1
		var qy = 0
		if direction.y > dash_input_threshold:
			qy = 1
		elif direction.y < -dash_input_threshold:
			qy = -1
		var qv = Vector2(qx, qy)
		if qv.length() > 0:
			dash_direction = _snap_to_eight(qv)
			dash_dir_enum = _vector_to_dir_enum(dash_direction)

# 处理冲刺释放
func _on_dash_released() -> void:
	if is_charging:
		_execute_dash()

# 蓄力超时
func _on_charge_timeout() -> void:
	if is_charging:
		_execute_dash()

# 执行冲刺
func _execute_dash() -> void:
	if not is_charging:
		return
	MusicPlayer.play_sfx("Dash")
	
	is_charging = false
	is_dashing = true
	if current_data.get("not_emit",true):
		GameEvents.player_dash.emit()

	var dash_speed = character.dash_speed
	
	# 确定冲刺方向
	if dash_direction.length() > 0.1:
		dash_direction = dash_direction.normalized()
		# 更新枚举以保持一致
		dash_dir_enum = _vector_to_dir_enum(dash_direction)
	else:
		dash_direction = character.heading
		dash_dir_enum = _vector_to_dir_enum(dash_direction)
	
	# 应用冲刺速度
	character.velocity = dash_direction * dash_speed
	character.is_dash = true
	# 在冲刺开始时临时断开普通移动回调（如果 InputHandler 存在），随后在短时间后重新连接以恢复左右移动
	if input_handler:
		# 确保 charging 用的 movement handler 已连接
		if not input_handler.movement_input.is_connected(_on_movement_input):
			input_handler.movement_input.connect(_on_movement_input)
		# 断开常规移动回调（由 move state 使用的回调）
		if input_handler.movement_input.is_connected(_on_movement_move_input):
			input_handler.movement_input.disconnect(_on_movement_move_input)

	# 启动恢复输入计时器（短于冲刺总时长），到期时重新连接普通移动回调
	if recover_timer:
		recover_timer.queue_free()
	recover_timer = Timer.new()
	recover_timer.wait_time = min(dash_input_recover_time, DASH_DURATION * 0.9)
	recover_timer.one_shot = true
	recover_timer.timeout.connect(func():
		if input_handler:
			if not input_handler.movement_input.is_connected(_on_movement_move_input):
				input_handler.movement_input.connect(_on_movement_move_input)
				# 恢复普通移动后断开蓄力监听，避免继续用蓄力方向影响移动
				if input_handler.movement_input.is_connected(_on_movement_input):
					input_handler.movement_input.disconnect(_on_movement_input)
		# 清理自身
		recover_timer.queue_free()
		recover_timer = null
	)
	add_child(recover_timer)
	recover_timer.start()
	
	# 开始冲刺计时器
	dash_timer.start()
	
	# 仅使用三种动画：up / down / front（玩家自动翻转处理左右）
	if dash_direction.y < 0:
		animation.play("dash_up")
	elif dash_direction.y > 0:
		animation.play("dash_down")
	else:
		animation.play("dash_front")

# 冲刺结束
func _on_dash_timeout() -> void:
	if character.velocity.y != 0:
		if character.velocity.y < 0:
			character.velocity.y *= 0.6
		change_state("fall")
		return
	change_state("move")

# 检查转换条件
func can_transition_to(target_state: String) -> bool:
	# 冲刺过程中不允许其他转换
	return true

# 获取状态数据
func get_state_data() -> Dictionary:
	return {
		"is_charging": is_charging,
		"is_dashing": is_dashing,
		"dash_direction": dash_direction,
		"charge_time_left": charge_timer.time_left if charge_timer else 0.0,
		"dash_time_left": dash_timer.time_left if dash_timer else 0.0
	}

func _on_movement_move_input(direction: Vector2) -> void:
	if not character.can_move:
		return
	
	var target_velocity = direction.x * character.speed
	character.velocity.x = move_toward(
		character.velocity.x, 
		target_velocity, 
		character.acceleation * get_physics_process_delta_time()
	)
## 调试信息
#func get_debug_info() -> String:
	#var phase = "charging" if is_charging else ("dashing" if is_dashing else "ending")
	#return "Dash State - Phase: %s, Direction: %s, Velocity: %s" % [
		#phase,
		#dash_direction,
		#character.velocity
	#]
